package com.apes.scm.settle.settle.model;

import com.alibaba.fastjson.annotation.JSONField;
import com.apes.framework.api.SpringManager;
import com.apes.framework.jpa.DefaultPersistListener;
import com.apes.framework.jpa.Model;
import com.apes.framework.jpa.comment.Comment;
import com.apes.framework.jpa.generator.ApesGenerator;
import com.apes.framework.plugin.soe.annotations.State;
import com.apes.framework.plugin.soe.annotations.States;
import com.apes.framework.util.ApesConst;
import com.apes.framework.util.Arith;
import com.apes.scm.account.account.model.Cooperation;
import com.apes.scm.masterdata.frame.model.Dept;
import com.apes.scm.masterdata.party.model.PartyRole;
import com.apes.scm.masterdata.party.repository.PartyRoleRepository;
import lombok.Getter;
import lombok.Setter;
import org.hibernate.annotations.DynamicInsert;
import org.hibernate.annotations.DynamicUpdate;
import org.hibernate.annotations.SelectBeforeUpdate;

import javax.persistence.*;
import javax.validation.constraints.NotNull;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;

@Getter
@Setter
@SelectBeforeUpdate
@DynamicInsert
@DynamicUpdate
@Entity
@EntityListeners(DefaultPersistListener.class)
@Table(name = Settle.CONST_TABLE_NAME)
public class Settle extends Model {
    public static final String CONST_TABLE_NAME = "acc_settle";

    @Id
    @Column(name = "id", length = 32)
    @ApesGenerator(code = CONST_TABLE_NAME, name = "结算单", prefix = "J")
    @Comment("结算单号")
    private String id; //结算单号

    @NotNull
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "company_id", referencedColumnName = "id")
    @Comment("公司编码")
    private PartyRole company; //公司

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "dept_id", referencedColumnName = "id")
    @Comment("部门编码")
    private Dept dept; //部门

    @NotNull
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "partner_id", referencedColumnName = "id", nullable = false)
    @Comment("业务伙伴编码")
    private PartyRole partner; //业务伙伴

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "cooperation_id", referencedColumnName = "id",nullable = false)
    @Comment("合作方式")
    private Cooperation cooperation; //合作方式

    @Comment("源单据")
    @Column(name = "origin", length = 30)
    private String origin;      // 平台供货结算与客户结算会写这个字段

    @Comment("源单据名称")
    @Column(name = "origin_Business_Name", length = 30)
    private String originBusinessName;


    @Comment("结算类型")
    @Column(name = "settle_type", length = 30)
    private String settleType;

    //@OneToOne(mappedBy = "settle", cascade = CascadeType.ALL, orphanRemoval = true)
    @Transient
    private TaxBill taxBill;  //税票登记

    public TaxBill getTaxBill() {
        if(taxBill != null) {
            taxBill.setSettle(this);
        }
        return taxBill;
    }

    @Column (name="purchase_amount" , nullable=false, columnDefinition = ApesConst.FIELD_MONEY_16_4_0)
    @Comment("采购金额")
    private double purchaseAmount = 0;  //货款金额-返利金额-变价金额

    public void calculatePurchaseAmount() {
        this.purchaseAmount = this.inboundAmount - this.returnAmount - this.changeAmount;
    }

    @Column (name="inbound_amount" , nullable=false, columnDefinition = ApesConst.FIELD_MONEY_16_4_0)
    @Comment("入库/销售金额")
    private double inboundAmount = 0; //货款金额

    public void changeInboundAmount(double amount) {
        this.inboundAmount += amount;
    }

    @Column (name="inbound_tax" , nullable=false, columnDefinition = ApesConst.FIELD_MONEY_16_4_0)
    @Comment("货款金额(税金)")
    private double inboundTax = 0; //货款金额税金 取数结算明细表税金合计

    public void changeInboundTax(double amount) {
        this.inboundTax += amount;
    }

    @Column (name="return_amount" , nullable=false, columnDefinition = ApesConst.FIELD_MONEY_16_4_0)
    @Comment("返厂/退货金额")
    private double returnAmount = 0; //返厂金额

    public void changeReturnAmount(double amount) {
        this.returnAmount += amount;
    }

    @Column (name="change_amount" , nullable=false, columnDefinition = ApesConst.FIELD_MONEY_16_4_0)
    @Comment("变价金额")
    private double changeAmount = 0; //变价金额

    public void changeChangeAmount(double amount) {
        this.changeAmount += amount;
    }

    @Column (name="rebate_amount" , nullable=false, columnDefinition = ApesConst.FIELD_MONEY_16_4_0)
    @Comment("返利金额")
    private double rebateAmount = 0; //返利金额

    public void changeRebateAmount(double amount) {
        this.rebateAmount += amount;
    }

    @Column (name="rebate_tax" , nullable=false, columnDefinition = ApesConst.FIELD_MONEY_16_4_0)
    @Comment("返利金额(税金)")
    private double rebateTax = 0; //返利金额(税金) 取结算返利明细的税金

    public void changeRebateTax(double amount) {
        this.rebateTax += amount;
    }

    @Column (name="settle_amount" , nullable=false, columnDefinition = ApesConst.FIELD_MONEY_16_4_0)
    @Comment("结算金额")
    private double settleAmount = 0; //结算金额

    public void changeSettleAmount(double amount) {
        this.settleAmount += amount;
    }

    @Column (name="settle_tax" , nullable=false, columnDefinition = ApesConst.FIELD_MONEY_16_4_0)
    @Comment("结算税金")
    private double settleTax = 0; //结算税金

    public void changeSettleTax(double amount) {
        this.settleTax += amount;
    }

    @Column (name="settle_tax_diff" , nullable=false, columnDefinition = ApesConst.FIELD_MONEY_16_4_0)
    @Comment("差异结算税金")
    private double settleTaxDiff = 0; //税金尾差

    @Column (name="payment_amount" , nullable=false, columnDefinition = ApesConst.FIELD_MONEY_16_4_0)
    @Comment("付款金额")
    private double paymentAmount = 0; //付款金额

    @Column (name="inventory_amount" , nullable=false, columnDefinition = ApesConst.FIELD_MONEY_16_4_0)
    @Comment("库存金额")
    private double inventoryAmount = 0;

    @Column (name="account_payable" , nullable=false, columnDefinition = ApesConst.FIELD_MONEY_16_4_0)
    @Comment("应付账款")
    private double accountPayable = 0;

    @Column (name="rebate_total" , nullable=false, columnDefinition = ApesConst.FIELD_MONEY_16_4_0)
    @Comment("当期返利金额")
    private double rebateTotal = 0;

    @Column (name="due_payable" , nullable=false, columnDefinition = ApesConst.FIELD_MONEY_16_4_0)
    @Comment("到期应付")
    private double duePayable = 0;

    @Column (name="prepaid_balance" , nullable=false, columnDefinition = ApesConst.FIELD_MONEY_16_4_0)
    @Comment("预付余额")
    private double prepaidBalance = 0;

    @Column(name = "note", length = 250)
    @Comment("备注")
    private String note; //备注

    @States(name = "结算状态", values = {
            @State(id = "sent", name = "结算申请"),
            @State(id = "approve", name = "已审核"),
            @State(id = "executive", name = "已执行")})
    @Column(name = "state", length = 10, nullable = false)
    private String state; //状态

    @States(name = "税票状态", values = {
            @State(id = "not", name = "未到票"),
            @State(id = "section", name = "部分到票"),
            @State(id = "already", name = "已到票")})
    @Column(name = "receipt_state", length = 10, nullable = false)
    private String receiptState; //税票状态

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "approve_uid", referencedColumnName = "id")
    @Comment("审核人")
    private PartyRole approveUID; //审核人

    @Column(name = "approve_date")
    @Comment("审核日期")
    private Date approveDate; //审核日期

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(name = "executive_uid", referencedColumnName = "id")
    @Comment("执行人")
    private PartyRole executiveUID; //执行人

    @Column(name = "executive_date")
    @Comment("执行日期")
    private Date executiveDate; //执行日期

    @Column(name = "discount_amount", nullable = false, columnDefinition = ApesConst.FIELD_16_4_0)
    @Comment("合计折扣金额")
    private double discountAmount;

    public double getDiscountAmount() {
        return this.settleItems.stream().mapToDouble(SettleItem::getDiscount).sum();
    }

    // mapping 入口
    @Transient
    private List<SettleItem> items;

    // 查询不做序列化
    @JSONField(serialize = false)
    @OneToMany(mappedBy = "settle", cascade = {CascadeType.MERGE,CascadeType.PERSIST,CascadeType.REFRESH},orphanRemoval = true)
    private List<SettleItem> settleItems = new ArrayList<>(); //结算商品

    public List<SettleItem> getSettleItems() {
        if(items != null) settleItems = items;
        if(settleItems == null) settleItems = new ArrayList<>();
        for (SettleItem item : settleItems) {
            item.setSettle(this);
        }
        return settleItems;
    }

    @OneToMany(mappedBy = "settle", cascade = {CascadeType.ALL},orphanRemoval = true)
    private List<SettleRebate> settleRebates = new ArrayList<>(); //结算返利

    public List<SettleRebate> getSettleRebates() {
        if(settleRebates == null) settleRebates = new ArrayList<>();
        for (SettleRebate item : settleRebates) {
            item.setSettle(this);
        }
        return settleRebates;
    }

    public void initAmt() {
        inboundAmount = 0;
        changeAmount = 0;
        returnAmount =0;
        rebateAmount = 0;
        settleAmount = 0;
        settleTax = 0;
        inboundTax = 0;
        rebateTax = 0;
        purchaseAmount = 0;
    }

    @Column(name = "invoiced_amount", columnDefinition = ApesConst.FIELD_MONEY_16_4_0)
    @Comment("已开票金额")
    private double invoicedAmount = 0;

    @States(name = "开票状态", values = {
            @State(id = "pending", name = "待开票"),
            @State(id = "in", name = "开票中"),
            @State(id = "finish", name = "已开票")})
    @Column(name = "invoice_state", length = 10)
    private String invoiceState;

    @Transient
    private PartyRole _creator;

    @Transient
    public PartyRole get_creator() {
        if(this.getCreator() == null) return null;
        return SpringManager.getBean(PartyRoleRepository.class).findOne(this.getCreator());
    }


    @Transient
    private double amtTotal;

    @Transient
    public double getAmtTotal() {
        if(Objects.isNull(taxBill)) return 0;
        return taxBill.getAmtTotal();
    }

    @Transient
    private double taxAmountLoss;

    @Transient
    public double getTaxAmountLoss() {
        if(Objects.isNull(taxBill)) return 0;
        double amount = taxBill.getTaxBillItems().stream().mapToDouble(TaxBillItem::getTaxAmount).sum() + taxBill.getTaxBillItems().stream().mapToDouble(TaxBillItem::getTaxLoss).sum();
        return amount;
    }

    @Transient
    private String inboundAmountText;   //货款金额前端展示
    @Transient
    private String rebateAmountText;   //返利金额前端展示
    @Transient
    private String settleAmountText;    //结算金额前端展示

    public String getInboundAmountText() {
        return String.format("%s (含税); %s (税金)", Arith.round(this.inboundAmount,2),Arith.round(this.inboundTax,2));
    }

    public String getRebateAmountText() {
        return String.format("%s (含税); %s (税金)", Arith.round(this.rebateAmount,2),Arith.round(this.rebateTax,2));

    }

    public String getSettleAmountText() {
        return String.format("%s (含税); %s (税金)", Arith.round(this.settleAmount,2),Arith.round(this.settleTax,2));
    }


}
